<template>
  <div class="container">
    <TableWrapper :title="'菜单管理'" :header="header">
      <template #header>
        <el-form ref="form" :model="query" label-width="120px" :inline="true">
          <el-form-item label="菜单名称：">
            <el-input
              style="width: 260px"
              v-model="query.menuName"
              placeholder="请输入菜单名称"
            ></el-input>
          </el-form-item>
          <el-form-item label="菜单状态：">
            <el-select
              v-model="query.status"
              style="width: 220px"
              placeholder="请选择菜单状态"
            >
              <el-option
                v-for="dict in dict.type.sys_normal_disable"
                :key="dict.value"
                :label="dict.label"
                :value="dict.value"
              />
            </el-select>
          </el-form-item>
          <el-form-item class="ml15">
            <el-button
              icon="el-icon-search"
              type="primary"
              @click="searchChange"
              >搜索</el-button
            >
            <el-button icon="el-icon-refresh-left" @click="searchReset"
              >重置</el-button
            >
          </el-form-item>
        </el-form>
      </template>

      <template #main>
        <div style="margin-bottom: 18px">
          <el-button
            type="primary"
            plain
            icon="el-icon-plus"
            @click="beforeOpen('add')"
            v-if="listType == 'menu'"
            v-hasPermission="['system:menu:add']"
            >新增</el-button
          >
          <el-button
            type="info"
            plain
            icon="el-icon-sort"
            @click="toggleExpandAll"
            >展开 / 折叠</el-button
          >
        </div>
        <el-table
          v-if="refreshTable"
          :data="data"
          :header-cell-style="headStyle"
          row-key="menuId"
          :height="screenHeight < 500 ? 500 : screenHeight - height"
          :default-expand-all="isExpandAll"
          @selection-change="selectionChange"
          :tree-props="{ children: 'children' }"
        >
          <el-table-column
            v-if="listType != 'menu'"
            type="selection"
            align="center"
            width="50"
          >
            <template v-slot="scope">
              <el-checkbox
                :value="isExist(scope.row)"
                :disabled="scope.row.type === 1"
                @change="(val) => selectChange(val, scope.row)"
              ></el-checkbox>
            </template>
          </el-table-column>
          <el-table-column align="center" prop="menuName" label="菜单名称">
          </el-table-column>
          <el-table-column align="center" prop="icon" label="图标">
            <template slot-scope="scope">
              <i :class="scope.row.icon"></i>
            </template>
          </el-table-column>
          <el-table-column align="center" prop="perms" label="权限标识">
          </el-table-column>
          <el-table-column align="center" prop="menuType" label="菜单类型">
            <template slot-scope="scope">
              <dict-tag
                :options="dict.type.sys_menu_type"
                :value="scope.row.menuType"
              />
            </template>
          </el-table-column>
          <el-table-column align="center" prop="component" label="组件路径">
          </el-table-column>
          <el-table-column align="center" prop="visible" label="菜单状态">
            <template slot-scope="scope">
              <dict-tag
                :options="dict.type.sys_normal_disable"
                :value="scope.row.visible"
              />
            </template>
          </el-table-column>
          <el-table-column align="center" prop="createTime" label="创建时间">
          </el-table-column>

          <el-table-column
            v-if="listType == 'menu'"
            align="center"
            label="修改"
          >
            <template slot-scope="scope">
              <el-button
                type="text"
                icon="el-icon-plus"
                @click="beforeOpen('add', scope.row)"
                v-hasPermission="['system:menu:add']"
                >添加</el-button
              >
              <el-button
                type="text"
                icon="el-icon-edit"
                @click="beforeOpen('edit', scope.row)"
                v-hasPermission="['system:menu:edit']"
                >编辑</el-button
              >
              <el-button
                @click="handelDel(scope.row)"
                type="text"
                v-hasPermission="['system:menu:delete']"
                icon="el-icon-delete"
                >删除</el-button
              >
            </template>
          </el-table-column>
        </el-table>
      </template>
    </TableWrapper>

    <!-- 修改框 -->
    <el-dialog
      :title="(ntype == 'add' ? '添加' : '修改') + '角色'"
      :visible.sync="dialogVisible"
      width="680px"
      append-to-body
    >
      <el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
        <el-row type="flex" style="flex-wrap: wrap">
          <el-col :span="24">
            <el-form-item label="上级菜单" prop="parentId">
              <treeselect
                v-model="form.parentId"
                :options="menuOptions"
                :normalizer="normalizer"
                :show-count="true"
                placeholder="选择上级菜单"
              />
            </el-form-item>
          </el-col>
          <el-col :span="24">
            <el-form-item label="菜单类型" prop="menuType">
              <el-radio-group v-model="form.menuType">
                <el-radio label="M">目录</el-radio>
                <el-radio label="C">菜单</el-radio>
                <el-radio label="F">按钮</el-radio>
              </el-radio-group>
            </el-form-item>
          </el-col>
          <el-col :span="24" v-if="form.menuType != 'F'">
            <el-form-item label="菜单图标" prop="icon">
              <el-input v-model="form.icon" placeholder="点击选择图标">
              </el-input>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="菜单名称" prop="menuName">
              <el-input v-model="form.menuName" placeholder="请输入菜单名称" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="显示排序" prop="orderNum">
              <el-input-number
                style="width: 100%"
                v-model="form.orderNum"
                controls-position="right"
                :min="0"
              />
            </el-form-item>
          </el-col>
          <el-col :span="12" v-if="form.menuType != 'F'">
            <el-form-item prop="isFrame">
              <span slot="label">
                <el-tooltip
                  content="选择是外链则路由地址需要以`http(s)://`开头"
                  placement="top"
                >
                  <i class="el-icon-question"></i>
                </el-tooltip>
                是否外链
              </span>
              <el-radio-group v-model="form.isFrame">
                <el-radio label="0">是</el-radio>
                <el-radio label="1">否</el-radio>
              </el-radio-group>
            </el-form-item>
          </el-col>
          <el-col :span="12" v-if="form.menuType != 'F'">
            <el-form-item prop="path">
              <span slot="label">
                <el-tooltip
                  content="访问的路由地址，如：`user`，如外网地址需内链访问则以`http(s)://`开头"
                  placement="top"
                >
                  <i class="el-icon-question"></i>
                </el-tooltip>
                路由地址
              </span>
              <el-input v-model="form.path" placeholder="请输入路由地址" />
            </el-form-item>
          </el-col>
          <el-col :span="12" v-if="form.menuType == 'C'">
            <el-form-item prop="component">
              <span slot="label">
                <el-tooltip
                  content="访问的组件路径，如：`system/user/index`，默认在`views`目录下"
                  placement="top"
                >
                  <i class="el-icon-question"></i>
                </el-tooltip>
                组件路径
              </span>
              <el-input v-model="form.component" placeholder="请输入组件路径" />
            </el-form-item>
          </el-col>
          <el-col :span="12" v-if="form.menuType != 'M'">
            <el-form-item prop="perms">
              <el-input
                v-model="form.perms"
                placeholder="请输入权限标识"
                maxlength="100"
              />
              <span slot="label">
                <el-tooltip
                  content="控制器中定义的权限字符，如：@PreAuthorize(`@ss.hasPermi('system:user:list')`)"
                  placement="top"
                >
                  <i class="el-icon-question"></i>
                </el-tooltip>
                权限字符
              </span>
            </el-form-item>
          </el-col>
          <el-col :span="12" v-if="form.menuType == 'C'">
            <el-form-item prop="query">
              <el-input
                v-model="form.query"
                placeholder="请输入路由参数"
                maxlength="255"
              />
              <span slot="label">
                <el-tooltip
                  content='访问路由的默认传递参数，如：`{"id": 1, "name": "zs"}`'
                  placement="top"
                >
                  <i class="el-icon-question"></i>
                </el-tooltip>
                路由参数
              </span>
            </el-form-item>
          </el-col>
          <el-col :span="12" v-if="form.menuType == 'C'">
            <el-form-item prop="isCache">
              <span slot="label">
                <el-tooltip
                  content="选择是则会被`keep-alive`缓存，需要匹配组件的`name`和地址保持一致"
                  placement="top"
                >
                  <i class="el-icon-question"></i>
                </el-tooltip>
                是否缓存
              </span>
              <el-radio-group v-model="form.isCache">
                <el-radio label="0">缓存</el-radio>
                <el-radio label="1">不缓存</el-radio>
              </el-radio-group>
            </el-form-item>
          </el-col>
          <el-col :span="12" v-if="form.menuType != 'F'">
            <el-form-item prop="visible">
              <span slot="label">
                <el-tooltip
                  content="选择隐藏则路由将不会出现在侧边栏，但仍然可以访问"
                  placement="top"
                >
                  <i class="el-icon-question"></i>
                </el-tooltip>
                显示状态
              </span>
              <el-radio-group v-model="form.visible">
                <el-radio
                  v-for="dict in dict.type.sys_show_hide"
                  :key="dict.value"
                  :label="dict.value"
                  >{{ dict.label }}</el-radio
                >
              </el-radio-group>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item prop="status">
              <span slot="label">
                <el-tooltip
                  content="选择停用则路由将不会出现在侧边栏，也不能被访问"
                  placement="top"
                >
                  <i class="el-icon-question"></i>
                </el-tooltip>
                菜单状态
              </span>
              <el-radio-group v-model="form.status">
                <el-radio
                  v-for="dict in dict.type.sys_normal_disable"
                  :key="dict.value"
                  :label="dict.value"
                  >{{ dict.label }}</el-radio
                >
              </el-radio-group>
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="dialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="handleSave()" :loading="loading"
          >保 存</el-button
        >
      </span>
    </el-dialog>
  </div>
</template>

<script>
import TableWrapper from "@/components/Table/TableWrapper.vue";
import { getList, remove, getNotice, add, update } from "@/api/menu.js";
import { getMenuAuth } from "@/api/system/role.js";

export default {
  components: { TableWrapper },
  dicts: ["sys_normal_disable", "sys_menu_type", "sys_show_hide"],
  props: {
    height: {
      type: Number,
      default: 365,
    },
    listType: {
      type: String,
      default: "menu",
    },
    header: {
      type: Boolean,
      default: true,
    },
    queryRoleId: {
      type: Number,
      default: 0,
    },
  },
  data() {
    return {
      // 搜索数据
      query: {},
      // 多选数据
      selectionList: [],
      // 表数据
      data: [],
      // 弹出框数据
      form: {},
      // 控制弹出框
      dialogVisible: false,
      // 操作类型
      ntype: "add",
      // 菜单选项
      menuOptions: [],
      // 按钮
      loading: false,
      // 校验结果
      validate: false,
      // 重新渲染表格状态
      refreshTable: true,
      // 是否展开，默认全部折叠
      isExpandAll: false,
      // 表单校验
      rules: {
        menuName: [
          { required: true, message: "菜单名称不能为空", trigger: "blur" },
        ],
        orderNum: [
          { required: true, message: "菜单顺序不能为空", trigger: "blur" },
        ],
        path: [
          { required: true, message: "路由地址不能为空", trigger: "blur" },
        ],
      },
      // 屏幕高度
      screenHeight: document.body.clientHeight,
    };
  },
  created() {
    // 重置表单
    this.resetForm();
    this.screenHeight = document.body.clientHeight;
    if (this.listType == "role" && this.queryRoleId != 0) {
      getMenuAuth(this.queryRoleId).then((res) => {
        this.selectionList = res.data;
        // 获取数据
        this.refreshChange();
      });
    } else {
      // 获取数据
      this.refreshChange();
    }
  },
  mounted() {
    // 把window.onresize事件挂在到mounted函数上,这里就会一直监听大小变化
    window.onresize = () => {
      return (() => {
        this.screenHeight = document.documentElement.clientHeight; // 高
      })();
    };
  },
  methods: {
    // 搜索重置
    searchReset() {
      this.query = {};
      this.refreshChange();
    },
    // 搜索点击
    searchChange() {
      this.refreshChange();
    },
    // 多选发生改变
    selectionChange(list) {
      // 清空数据
      this.selectionClear();
      if (list.length > 0) {
        this.filterChildren(list);
      }
    },
    // 过滤子数据
    filterChildren(children) {
      children.forEach((child) => {
        this.selectionList.push({ menuId: child.menuId });
        if (child.children.length > 0) {
          this.filterChildren(child.children);
        }
      });
    },
    // 判断是否有被选中
    isExist(row) {
      return this.selectionList.filter((v) => v.menuId == row.menuId) != false;
    },
    // 修改时触发，value 表示是否选中，row表示当前行
    selectChange(val, row) {
      if (val) {
        this.selectionList.push({ menuId: row.menuId });
      } else {
        // 过滤数据
        this.selectionList = this.selectionList.filter(
          (item) => row.menuId != item.menuId
        );
      }
      // 调用判断方法，
      this.isExist(row);
    },
    // 刷新数据
    refreshChange() {
      this.onLoad(this.query);
    },
    // 重置表单
    resetForm() {
      this.form = {
        menuId: undefined,
        parentId: 0,
        menuName: undefined,
        icon: undefined,
        menuType: "M",
        orderNum: 0,
        isFrame: "1",
        isCache: "0",
        visible: "0",
        status: "0",
      };
    },
    // 展开/折叠操作
    toggleExpandAll() {
      this.refreshTable = false;
      this.isExpandAll = !this.isExpandAll;
      this.$nextTick(() => {
        this.refreshTable = true;
      });
    },
    // 点击全选触发
    selectionClear() {
      this.selectionList = [];
    },

    // 处理表单开启
    beforeOpen(ntype, row) {
      this.ntype = ntype;
      // 重置标签
      this.resetForm();

      // 如果是编辑
      if (["edit", "view"].includes(ntype)) {
        // 查询详情
        getNotice(row.menuId).then((res) => {
          this.form = res.data;
        });
      }

      if (ntype == "add" && row) {
        this.form.parentId = row.menuId;
      }

      // 修改按钮状态
      this.loading = false;
      // 打开提交框
      this.dialogVisible = true;
    },
    // 添加数据
    handleSave() {
      // 校验表单
      this.validateForm();

      if (!this.validate) {
        return;
      }

      if (this.ntype == "add") {
        this.sendAjax(add, this.form);
      } else {
        this.sendAjax(update, this.form);
      }
    },
    // 校验表单
    validateForm() {
      this.$refs.formRef.validate((valid) => {
        if (valid) {
          this.validate = true;
          return true;
        } else {
          this.validate = false;
          return false;
        }
      });
    },
    // 发送 ajax 请求
    sendAjax(Interface, row) {
      // 调用接口发送请求
      Interface(row).then(
        (res) => {
          if (res.code == 200) {
            this.$modal.msgSuccess(res.msg);
            // 关闭弹窗
            this.dialogVisible = false;
            // 刷新列表
            this.refreshChange();
          } else {
            this.$modal.msgError(res.msg);
          }
          this.loading = false;
        },
        () => {
          this.$modal.msgError("系统错误，请稍后尝试！");
        }
      );
    },
    // 删除数据
    handelDel(row) {
      this.$modal
        .confirm("确定将选择数据删除?")
        .then(() => {
          return remove(row.menuId);
        })
        .then((res) => {
          if (res.code == 200) {
            this.refreshChange();
            this.$modal.msgSuccess("操作成功!");
          } else {
            this.$modal.msgError(res.msg);
          }
        });
    },
    // 重载数据
    onLoad(params = {}) {
      let values = {
        ...params,
        // 排序字段
        orderByColumn: "create_time",
        // 排序方式 desc 降序 asc 升序
        isAsc: "asc",
      };

      this.loading = true;
      getList(Object.assign(values, this.query)).then((res) => {
        this.data = res.data;
        this.loading = false;
        this.menuOptions = [];
        const menu = { menuId: 0, menuName: "主类目", children: this.data };
        this.menuOptions.push(menu);
        if (this.listType == "menu") {
          this.selectionClear();
        }
      });
    },
    /** 转换菜单数据结构 */
    normalizer(node) {
      if (node.children && !node.children.length) {
        delete node.children;
      }
      return {
        id: node.menuId,
        label: node.menuName,
        children: node.children,
      };
    },
    // 自定义表头颜色
    headStyle({ row, rowIndex }) {
      if (rowIndex === 0) {
        return {
          backgroundColor: "#F8FAFF",
          fontWeight: 800,
          color: "#515a6e",
        };
      }
    },
  },
};
</script>
